#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <malloc.h>
#include <unistd.h>

#include "common.h"
#include "upgrade_acm32.h"
#include "ofprint_common.h"



static int acm32_parseProtocal(ACM32_UPGRADE_PARAM *this, unsigned char *data, int len)
{
    uint8 getchar = 0;
    ACM32_UP_PROT_PACKET *p = &(this->prot_packet_usb);
    int32 ret = -1;
    //D_DBG("received data len = %d:\n", len);

#if 0
    for(int i = 0; i < len; i++)
    {
        DBG("0x%02x ", data[i]);
    }
    DBG("\n");
#endif

/*对USB的命令数据进行处理*/
    for(int i = 0; i < len; i++)
    {
        getchar = data[i];

        switch (p->prot_state)
        {
            case ACM32_UP_PACKET_IDLE:
                if (getchar == 0xAA)
                {
                    p->prot_state = ACM32_UP_PACKET_TYPE;
                    p->prot_head = getchar;
                    this->usb_recv_cnt = 0;
                    this->usb_recv_data[(this->usb_recv_cnt)++]=getchar;
                }
                break;
            case ACM32_UP_PACKET_TYPE:
                p->prot_type = getchar;
                p->prot_state = ACM32_UP_PACKET_SIZE1;
                this->usb_recv_data[(this->usb_recv_cnt)++]=getchar;
                break;
            case ACM32_UP_PACKET_SIZE1:
                p->prot_size  = 0;
                p->prot_size |= getchar;
                p->prot_state = ACM32_UP_PACKET_SIZE2;
                this->usb_recv_data[(this->usb_recv_cnt)++]=getchar;
                break;
            case ACM32_UP_PACKET_SIZE2: //包长度 = 数据内容长度 + 校验位长度
                p->prot_size |= (getchar<<8);
                //D_DBG("packet size = %d\n", p->prot_size);
                p->prot_data_cnt = 0;
                if (p->prot_size > 0)               //有数据
                {
                    p->prot_state = ACM32_UP_PACKET_DATA;
                }
                else if (p->prot_size == 0) //无数据，直接到校验位
                {
                    p->prot_state = ACM32_UP_PACKET_BCC;
                }
                else
                {
                    p->prot_state = ACM32_UP_PACKET_IDLE;
                }

                this->usb_recv_data[(this->usb_recv_cnt)++] = getchar;
                break;
            case ACM32_UP_PACKET_DATA:
                p->prot_data[p->prot_data_cnt] = getchar;
                p->prot_data_cnt++;

                if(p->prot_size <= p->prot_data_cnt)
                {
                    p->prot_state = ACM32_UP_PACKET_BCC;
                }

                this->usb_recv_data[(this->usb_recv_cnt)++]=getchar;
                break;
            case ACM32_UP_PACKET_BCC:
                p->prot_bcc  = getchar;
                p->prot_state = ACM32_UP_PACKET_END;

                this->usb_recv_data[(this->usb_recv_cnt)++]=getchar;
                break;
            case ACM32_UP_PACKET_END:
                p->prot_end = getchar;
                this->usb_recv_data[(this->usb_recv_cnt)++] = getchar;
                //D_DBG("bcc = %d\n", this->Check_BCC(usb_recv_data, usb_recv_cnt));

                if((0x55 == p->prot_end)&&(0 == com_Check_BCC(this->usb_recv_data, this->usb_recv_cnt)))
                {
                    p->prot_respond = 0;
                    p->prot_state = ACM32_UP_PACKET_RECV_SUCCESS;
                    //D_DBG("Recv %d bytes data from device.\n", usb_recv_cnt);
                    this->usb_recv_cnt=0;
                    ret = 0;
                    return ret;
                }
                else
                {
                    WD_ERR("Recv data from device error!!!\n");
                    p->prot_state = ACM32_UP_PACKET_ERROR;
                }
                break;
            default:
                break;
        }
    }

    return ret;
}

#if 0
static int acm32_readEFlash(ACM32_UPGRADE_PARAM *this, unsigned int addr, unsigned char len)
{
    uint8 buf[100] = {0xAA, 0xD0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55};
    int cmd_len = 11;
    INTF_USB_CMD_STRUCT usb_cmd;

    buf[4] = addr & 0xff;
    buf[5] = (addr>>8) & 0xff;
    buf[6] = (addr>>16) & 0xff;
    buf[7] = (addr>>24) & 0xff;
    buf[8] = len;
    buf[9] = com_Check_BCC(buf, cmd_len);

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf;
    usb_cmd.write_len = cmd_len;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    uint8 buf_read[500] = {0};
    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf_read;
    usb_cmd.read_len = len + 10;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();
END:
    return 0;
}
#endif

static int acm32_eraseEFlash(ACM32_UPGRADE_PARAM *this)
{
    uint8 buf[500] = {0xAA, 0xD3, 0x00, 0x00, 0x00, 0x55};
    int cmd_len = 4+2;
    INTF_USB_CMD_STRUCT usb_cmd;
    int ret = -1;

    buf[4] = com_Check_BCC(buf, cmd_len);

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf;
    usb_cmd.write_len = cmd_len;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    ACM32_UP_PROT_PACKET *p = &(this->prot_packet_usb);
    uint8 buf_read[500] = {0};
    int read_len = 0;

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf_read;
    usb_cmd.read_len = 64;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    read_len = usb_cmd.read_len;
    if(0 < read_len)
    {
        //D_DBG("read %d byte.\n", read_len);
        p->prot_state = ACM32_UP_PACKET_IDLE;
        if((0 == acm32_parseProtocal(this, buf_read, read_len))\
            &&(ACM32_UP_PACKET_RECV_SUCCESS == p->prot_state))
        {
            //memcpy(this->dev_sn, p->prot_data, p->prot_data_cnt);
            if((1 == p->prot_data_cnt)&&(0 == p->prot_data[0]))
                ret = 0;
        }
        p->prot_state = ACM32_UP_PACKET_IDLE;
    }
    else
    {
        WD_ERR("read response failed!!!\n");
    }
END:
    return ret;
}


static int acm32_downloadCodeToEFlash(ACM32_UPGRADE_PARAM *this, unsigned int addr, char *data, int len)
{
    uint8 buf[500] = {0xAA, 0xD7};
    int cmd_len = 4 + 4 + len + 2;
    INTF_USB_CMD_STRUCT usb_cmd;
    int ret = -1;

    buf[2] = (4+len)&0xff;
    buf[3] = ((4+len)>>8)&0xff;
    buf[4] = addr & 0xff;
    buf[5] = (addr>>8) & 0xff;
    buf[6] = (addr>>16) & 0xff;
    buf[7] = (addr>>24) & 0xff;
    memcpy(&buf[8], data, len);

    //D_DBG("cmd_len = %d, bcc = 0x%02x", cmd_len, Check_BCC(buf, cmd_len));
    buf[4+4+len+1] = 0x55;
    buf[4+4+len] = com_Check_BCC(buf, cmd_len);

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf;
    usb_cmd.write_len = ACM32_BOOT_DOWNLOAD_DATA_LEN_MAX+10;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    ACM32_UP_PROT_PACKET *p = &(this->prot_packet_usb);
    uint8 buf_read[500] = {0};
    int read_len = 0;

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf_read;
    usb_cmd.read_len = 64;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    read_len = usb_cmd.read_len;
    if(0 < read_len)
    {
        //D_DBG("read %d byte.\n", read_len);
        p->prot_state = ACM32_UP_PACKET_IDLE;
        if((0 == acm32_parseProtocal(this, buf_read, read_len))\
            &&(ACM32_UP_PACKET_RECV_SUCCESS == p->prot_state))
        {
            //memcpy(this->dev_sn, p->prot_data, p->prot_data_cnt);
            if((1 == p->prot_data_cnt)&&(0 == p->prot_data[0]))
                ret = 0;
        }
        p->prot_state = ACM32_UP_PACKET_IDLE;
    }
    else
    {
        WD_ERR("read response failed!!!\n");
    }
END:
    return ret;
}

static int acm32_readCRC(ACM32_UPGRADE_PARAM *this, unsigned int addr, int len)
{
    uint8 buf[500] = {0xAA, 0xA6, 0x08, 0x00};
    int cmd_len = 4+4+4+2;
    INTF_USB_CMD_STRUCT usb_cmd;
    int ret = -1;

    buf[4] = addr & 0xff;
    buf[5] = (addr>>8) & 0xff;
    buf[6] = (addr>>16) & 0xff;
    buf[7] = (addr>>24) & 0xff;

    buf[8] = len & 0xff;
    buf[9] = (len>>8) & 0xff;
    buf[10] = (len>>16) & 0xff;
    buf[11] = (len>>24) & 0xff;

    buf[13] = 0x55;
    buf[12] = com_Check_BCC(buf, cmd_len);

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf;
    usb_cmd.write_len = 250;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    ACM32_UP_PROT_PACKET *p = &(this->prot_packet_usb);
    uint8 buf_read[500] = {0};
    int read_len = 0;

    this->crc_value_dev = 0;

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf_read;
    usb_cmd.read_len = 64;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    read_len = usb_cmd.read_len;
    if(0 < read_len)
    {
        D_DBG("read %d byte.\n", read_len);

        p->prot_state = ACM32_UP_PACKET_IDLE;
        if((0 == acm32_parseProtocal(this, buf_read, read_len))\
            &&(ACM32_UP_PACKET_RECV_SUCCESS == p->prot_state))
        {
            this->crc_value_dev = (p->prot_data[0]) | ((p->prot_data[1])<<8);
            ret = 0;
        }
        p->prot_state = ACM32_UP_PACKET_IDLE;
    }
    else
    {
        WD_ERR("read response failed!!!\n");
    }
END:
    return ret;
}

static int acm32_downloadCRCValue(ACM32_UPGRADE_PARAM *this, unsigned int len, unsigned short crc, unsigned int addr)
{
    uint8 buf[500] = {0xAA, 0xD9, 0x0A, 0x00};
    int cmd_len = 4+4+2+4+2;
    INTF_USB_CMD_STRUCT usb_cmd;
    int ret = -1;

    buf[4] = len & 0xff;
    buf[5] = (len>>8) & 0xff;
    buf[6] = (len>>16) & 0xff;
    buf[7] = (len>>24) & 0xff;

    buf[8] = crc & 0xff;
    buf[9] = (crc>>8) & 0xff;

    buf[10] = addr & 0xff;
    buf[11] = (addr>>8) & 0xff;
    buf[12] = (addr>>16) & 0xff;
    buf[13] = (addr>>24) & 0xff;

    buf[15] = 0x55;
    buf[14] = com_Check_BCC(buf, cmd_len);

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf;
    usb_cmd.write_len = 250;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    ACM32_UP_PROT_PACKET *p = &(this->prot_packet_usb);
    uint8 buf_read[500] = {0};
    int read_len = 0;

    this->crc_value_dev = 0;

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf_read;
    usb_cmd.read_len = 64;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    read_len = usb_cmd.read_len;
    if(0 < read_len)
    {
        D_DBG("read %d byte.\n", read_len);

        p->prot_state = ACM32_UP_PACKET_IDLE;
        if((0 == acm32_parseProtocal(this, buf_read, read_len))\
            &&(ACM32_UP_PACKET_RECV_SUCCESS == p->prot_state))
        {
            if((1 == p->prot_data_cnt)&&(0 == p->prot_data[0]))
                ret = 0;
        }
        p->prot_state = ACM32_UP_PACKET_IDLE;
    }
    else
    {
        WD_ERR("read response failed!!!\n");
    }
END:
    return ret;
}

#if 0
static int acm32_checkCRC(ACM32_UPGRADE_PARAM *this)
{
    return 0;
}
#endif

static int acm32_securityCode(ACM32_UPGRADE_PARAM *this)
{
    uint8 buf[500] = {0xAA, 0xCC, 0x00, 0x00, 0x00, 0x55};
    int cmd_len = 4+2;
    INTF_USB_CMD_STRUCT usb_cmd;
    int ret = -1;

    buf[4] = com_Check_BCC(buf, cmd_len);

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf;
    usb_cmd.write_len = cmd_len;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    ACM32_UP_PROT_PACKET *p = &(this->prot_packet_usb);
    uint8 buf_read[500] = {0};
    int read_len = 0;
    usleep(30 * 1000);

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf_read;
    usb_cmd.read_len = 64;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    read_len = usb_cmd.read_len;
    if(0 < read_len)
    {
        p->prot_state = ACM32_UP_PACKET_IDLE;
        if((0 == acm32_parseProtocal(this, buf_read, read_len))\
            &&(ACM32_UP_PACKET_RECV_SUCCESS == p->prot_state))
        {
            //memcpy(this->dev_sn, p->prot_data, p->prot_data_cnt);
            if((1 == p->prot_data_cnt)&&(0 == p->prot_data[0]))
                ret = 0;
        }
        p->prot_state = ACM32_UP_PACKET_IDLE;
    }
    else
    {
        WD_ERR("read response failed!!!\n");
    }
END:
    return ret;
}

static int acm32_runAPP(ACM32_UPGRADE_PARAM *this)
{
    uint8 buf[500] = {0xAA, 0xE3, 0x00, 0x00, 0x00, 0x55};
    int cmd_len = 4+2;
    INTF_USB_CMD_STRUCT usb_cmd;
    int ret = -1;

    buf[4] = com_Check_BCC(buf, cmd_len);

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf;
    usb_cmd.write_len = cmd_len;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    ACM32_UP_PROT_PACKET *p = &(this->prot_packet_usb);
    uint8 buf_read[500] = {0};
    int read_len = 0;

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf_read;
    usb_cmd.read_len = 64;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    read_len = usb_cmd.read_len;
    if(0 < read_len)
    {
        //D_DBG("read %d byte.\n", read_len);
        p->prot_state = ACM32_UP_PACKET_IDLE;
        if((0 == acm32_parseProtocal(this, buf_read, read_len))\
            &&(ACM32_UP_PACKET_RECV_SUCCESS == p->prot_state))
        {
            //memcpy(this->dev_sn, p->prot_data, p->prot_data_cnt);
            if((1 == p->prot_data_cnt)&&(0 == p->prot_data[0]))
                ret = 0;
        }
        p->prot_state = ACM32_UP_PACKET_IDLE;
    }
    else
    {
        WD_ERR("read response failed!!!\n");
    }

END:
    return ret;
}

#if 0
static int acm32_selfTest(ACM32_UPGRADE_PARAM *this)
{
    return 0;
}
#endif

int acm32_readSN(ACM32_UPGRADE_PARAM *this)
{
    uint8 buf[500] = {0xAA, 0xA0, 0x00, 0x00, 0x00, 0x55};
    int cmd_len = 4+2;
    INTF_USB_CMD_STRUCT usb_cmd;
    int ret = -1;

    buf[4] = com_Check_BCC(buf, cmd_len);

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf;
    usb_cmd.write_len = 250;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    ACM32_UP_PROT_PACKET *p = &(this->prot_packet_usb);

    memset(this->dev_sn, 0x00, 64);
    uint8 buf_read[500] = {0};
    int read_len = 0;

    memset((uint8 *)&usb_cmd, 0x00, sizeof(INTF_USB_CMD_STRUCT));
    usb_cmd.buff = buf_read;
    usb_cmd.read_len = 64;
    usb_cmd.timeout = ACM32_BOOT_TRANSFER_TIMEOUT;

    if(DRV_OK != intf_usb_bulk_transfer(&(this->usb_handle), &usb_cmd))
    {
        WD_ERR("intf_usb_bulk_transfer: FAIL!\n");
        goto END;
    }
    ACM32_TRANSFER_DELAY();

    read_len = usb_cmd.read_len;
    if(0 < read_len)
    {
        D_DBG("read %d byte.\n", read_len);
        p->prot_state = ACM32_UP_PACKET_IDLE;
        if((0 == acm32_parseProtocal(this, buf_read, read_len))\
            &&(ACM32_UP_PACKET_RECV_SUCCESS == p->prot_state))
        {
            memcpy(this->dev_sn, p->prot_data, p->prot_data_cnt);
            ret = 0;
        }
        p->prot_state = ACM32_UP_PACKET_IDLE;
    }
    else
    {
        WD_ERR("read response failed!!!\n");
    }
END:
    return ret;
}


//返回值为-2则表示无法升级，返回值为-1表示升级失败，可尝试重新升级
int32 acm32_upgrade_and_run(ACM32_UPGRADE_PARAM *this, char *file_path)
{
    //打开并读取文件
    FILE *file;
    int file_size = 0;
    int read_size = 0;
    int ret = -1;

    if((NULL == this) || (NULL == file_path))
    {
        WD_ERR("the param is ERROR!!!\n");
        ret = -2;
        goto END;
    }

    if(NULL == strstr(file_path, ACM32FP_V))
    {
        WD_ERR("file_path = %s, ERROR!\n", file_path);
        ret = -2;
        goto END;
    }

    file_size = com_get_file_size(file_path);
    if((ACM32_FW_FILE_SIZE_MIN >= file_size) || (ACM32_FW_FILE_SIZE_MAX < file_size))//此处最大文件大小待确认
    {
        WD_ERR("%s file_size = %d, error!\n", file_path, file_size);
        ret = -2;
        goto END;
    }
    D_DBG("file_size = %d\n", file_size);

    file = fopen(file_path, "rb");
    if(NULL == file)
    {
        WD_ERR("%s open failed!\n", file_path);
        ret = -2;//文件未打开则直接取消升级，modified by hcq, 20230425
        goto END;
    }

    uint8 *file_data = (uint8 *)calloc(1, file_size);
    if(NULL == file_data)
    {
        WD_ERR("calloc file_data: FAIL!\n");
        goto FILE_OPEN_SUCCESS;
    }

    read_size = fread(file_data, 1, file_size, file);
    D_DBG("read_size = %d\n", read_size);
    if(file_size != read_size)
    {
        WD_ERR("file_size = %d, read_size = %d, read file failed!\n", file_size, read_size);
        goto CALLOC_FILE_DATA_SUCCESS;
    }

    char *data = (char *)file_data;
    int addr = 0;
    int size = file_size;
    this->crc_value_file = com_CRC16_X25(data, size);
    this->crc_value_dev = 0;
    D_DBG("size = %d\n", size);
    D_DBG("crc_value = 0x%04x\n", this->crc_value_file);

    if(DRV_OK != intf_usb_open(&(this->usb_id), &(this->usb_handle)))
    {
        WD_ERR("intf_usb_open: FAIL!\n");
        goto CALLOC_FILE_DATA_SUCCESS;
    }

    if(0 > acm32_eraseEFlash(this))
    {
        WD_ERR("acm32_eraseEFlash failed!!!\n");
        goto INTF_USB_OPEN_SUCCESS;
    }

    int count = size/ACM32_BOOT_DOWNLOAD_DATA_LEN_MAX;
    for(int i = 0; i < count; i++)
    {
        if(0 != acm32_downloadCodeToEFlash(this, addr, data+addr, ACM32_BOOT_DOWNLOAD_DATA_LEN_MAX))
        {
            WD_ERR("acm32_downloadCodeToEFlash: failed!!!\n");
            goto INTF_USB_OPEN_SUCCESS;
        }
        addr += ACM32_BOOT_DOWNLOAD_DATA_LEN_MAX;
    }

    if((0 < size%ACM32_BOOT_DOWNLOAD_DATA_LEN_MAX)
        && (0 != acm32_downloadCodeToEFlash(this, addr, data+addr, size%ACM32_BOOT_DOWNLOAD_DATA_LEN_MAX)))
    {
        WD_ERR("acm32_downloadCodeToEFlash: failed!!!\n");
        goto INTF_USB_OPEN_SUCCESS;
    }

    if(0 != acm32_readCRC(this, 0x00000000, size))
    {
        WD_ERR("acm32_readCRC: failed!!!\n");
        goto INTF_USB_OPEN_SUCCESS;
    }

    if(this->crc_value_dev != this->crc_value_file)
    {
        WD_ERR("check CRC: error!!!\n");
        goto INTF_USB_OPEN_SUCCESS;
    }

    if(0 != acm32_downloadCRCValue(this, size, this->crc_value_file, 0x00))
    {
        WD_ERR("acm32_downloadCRCValue: FAIL!\n");
        goto INTF_USB_OPEN_SUCCESS;
    }

    if(0 > acm32_securityCode(this))
    {
        WD_ERR("acm32_securityCode: FAIL!\n");
        goto INTF_USB_OPEN_SUCCESS;
    }

    ret = 0;
    WD_LOG("acm32 upgrade: SUCCESS.\n");
    if(0 == acm32_runAPP(this))
    {
        WD_LOG("acm32_runAPP: SUCCESS.\n");
    }

INTF_USB_OPEN_SUCCESS:
    intf_usb_close(&(this->usb_handle));
CALLOC_FILE_DATA_SUCCESS:
    free(file_data);
FILE_OPEN_SUCCESS:
    fclose(file);
END:
    WD_DBG("acm32_upgrade_and_run end.\n");
    return ret;
}


int32 acm32_upgrade_module_init(ACM32_UPGRADE_PARAM *this)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    memset((uint8 *)this, 0x00, sizeof(ACM32_UPGRADE_PARAM));
    this->usb_handle.handle = NULL;
    this->usb_id.idVendor = ACM32_BOOT_USB_VID;
    this->usb_id.idProduct = ACM32_BOOT_USB_PID;

    return DRV_OK;
}


